package com.piece.core.authentication.provider;

import com.piece.core.authentication.exception.PasswordNotMatchException;
import com.piece.core.authentication.exception.UserNotMatchException;
import com.piece.core.web.authority.token.UsernameAuthenticationToken;
import com.piece.core.framework.util.cache.CacheFactory;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.core.web.properties.SecurityProperties;
import com.piece.core.framework.support.dto.UserDetailDTO;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;

public class AuthenticationUsernameProvider implements AuthenticationProvider {

    private final String LOGIN_COUNT = "login_count_";

    private SecurityProperties securityProperties;

    private UserDetailsService userDetailsService;

    private CacheFactory cacheFactory;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernameAuthenticationToken authenticationToken = (UsernameAuthenticationToken) authentication;
        String username = authentication.getPrincipal().toString();
        String password = authentication.getCredentials().toString();

        UserDetailDTO user;
        try {
            user = (UserDetailDTO) userDetailsService.loadUserByUsername(username);
        } catch (Exception e) {
            throw new UserNotMatchException();
        }

        if (null == user) {
            throw new UserNotMatchException();
        }

        // 登陆次数验证
        if (null != cacheFactory) {
            ProviderUtil.authLoginCount(cacheFactory, securityProperties, LOGIN_COUNT + user.getId());
        }

        // 密码校验
        if (!matches(user, password)) {
            throw new PasswordNotMatchException();
        }

        // 清空登陆次数统计
        if (null != cacheFactory) {
            cacheFactory.get().delete(LOGIN_COUNT + user.getId());
        }

        UsernameAuthenticationToken authenticationResult = new UsernameAuthenticationToken(user.getLoginName(), password, user, user.getAuthorities(), authenticationToken.getClientId());
        return authenticationResult;
    }

    public boolean matches(UserDetailDTO user, String newPassword) {
        return user.getPassword().equals(MD5Coder.decode(user.getLoginName() + newPassword + user.getSalt()));
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernameAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public void setSecurityProperties(SecurityProperties securityProperties) {
        this.securityProperties = securityProperties;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public void setCacheFactory(CacheFactory cacheFactory) {
        this.cacheFactory = cacheFactory;
    }
}
